package com.hc.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hc.common.service.RedisService;
import com.hc.constant.BaseStatus;
import com.hc.constant.RedisConst;
import com.hc.constant.UserConst;
import com.hc.domain.Permission;
import com.hc.domain.Role;
import com.hc.domain.RolePermission;
import com.hc.domain.User;
import com.hc.domain.UserPermission;
import com.hc.mapper.UserMapper;
import com.hc.res.MenuItem;
import com.hc.res.MenuItemAuth;
import com.hc.service.PermissionService;
import com.hc.service.RolePermissionService;
import com.hc.service.RoleService;
import com.hc.service.UserPermissionService;
import com.hc.service.UserService;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author hecai
 */
@Service
@CacheConfig(cacheManager = "cacheManager")
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    @Resource
    RedisService<User> userRedisServiceImpl;
    @Resource
    private RoleService roleService;

    @Resource
    private UserPermissionService userPermissionService;
    @Resource
    private PermissionService permissionService;
    @Resource
    private RolePermissionService rolePermissionService;

    @Override
    public MenuItemAuth getAuthoritiesPermissions(String username) {
        List<MenuItem> menuItemList = new ArrayList<>();

        //根据用户名查找用户
        User user = baseMapper.selectOne(new QueryWrapper<User>()
                .select("id", "username", "password", "nickname", "email", "tel", "gender", "birth", "avatar", "role_id")
                .eq("username", username)
                .eq("status", BaseStatus.Status.ok));

        //查找角色
        Role role = roleService.getOne(new QueryWrapper<Role>()
                .select("id", "name", "code")
                .eq("status", BaseStatus.Status.ok)
                .eq("id", user.getRoleId()));
        menuItemList.add(MenuItem.builder()
                .id(role.getId())
                .name(role.getName())
                .code(role.getCode())
                .pid(-1) // -1表示是角色
                .build());
        String authorities = "ROLE_" + role.getCode() + ",";

        // 当前用户拥有的权限permission的id的集合
        List<Integer> permissionIdList = new ArrayList<>();
        //在tb_role_permission中查找Role所对应的角色
        List<RolePermission> rolePermissionList = rolePermissionService.list(new QueryWrapper<RolePermission>()
                .select("permission_id")
                .eq("role_id", role.getId())
                .eq("status", BaseStatus.Status.ok));
        List<Integer> pid1 = rolePermissionList.stream().map(item -> item.getPermissionId()).collect(Collectors.toList());
        permissionIdList.addAll(pid1);
        //在tb_user_permission中查找权限
        List<UserPermission> userPermissionList = userPermissionService.list(new QueryWrapper<UserPermission>()
                .select("permission_id")
                .eq("user_id", user.getId())
                .eq("status", BaseStatus.Status.ok));
        List<Integer> pid2 = userPermissionList.stream().map(item -> item.getPermissionId()).collect(Collectors.toList());
        permissionIdList.addAll(pid2);

        //查找具体的权限信息
        List<Permission> permissionList = permissionService.list(new QueryWrapper<Permission>()
                .select("id", "name", "code", "pid")
                .eq("status", BaseStatus.Status.ok)
                .in("id", permissionIdList));
        List<MenuItem> permissionMenuItemList = permissionList.stream().map(item -> MenuItem.builder()
                .id(item.getId())
                .name(item.getName())
                .code(item.getCode())
                .pid(item.getPid())
                .build()).collect(Collectors.toList());
        menuItemList.addAll(permissionMenuItemList);

        String permissions = permissionList.stream().map(item -> item.getCode() + ",").collect(Collectors.joining());
        System.out.println(permissions);
        //去掉最后一个逗号
        permissions = permissions.substring(0, permissions.length() - 1);

        System.out.println(authorities + permissions);
        MenuItemAuth res = MenuItemAuth.builder()
                .menuItemList(menuItemList)
                .auth(authorities + permissions)
                .password(user.getPassword())
                .build();
        return res;
    }

    @Override
    public List<User> findTopActiveUsers(Integer n) {
        IPage<User> page = new Page<>(1, n);
        IPage<User> userPage = baseMapper.selectPage(page, new QueryWrapper<User>()
                .eq("status", UserConst.Status.ok)
                .orderByDesc("priority"));
        List<User> userList = userPage.getRecords();
        userList = userList.subList(0, UserConst.TOP_ACTIVE_COUNT);
        for (User user : userList) {
            //userRedisServiceImpl.set(RedisConst.User + "::" + user.getId(), user, -1L);
            //将User信息按钮Priority字段排序，以zset的形式缓存到Redis中
            userRedisServiceImpl.zsetAdd(RedisConst.User, user, Double.valueOf(user.getPriority()));
        }
        return userList;
    }

    @Override
    @Cacheable(value = RedisConst.User, key = "#id", condition = "#flag==true", unless = "#result==null")
    public User findUserById(Integer id, Boolean flag) {
        //查询，先从Redis中查：如果Redis中有直接返回，如果Redis中没有则从数据库中查，查到之后将数据缓存到Redis中
        User user = baseMapper.selectById(id);
        return user;
    }

    @Override
    public User login(String username, String password) {
        User user = baseMapper.selectOne(new QueryWrapper<User>().eq("username", username).eq("password", password));
        if (user != null) {
            userRedisServiceImpl.set(RedisConst.User + "::" + user.getId(), user);
        }
        return user;
    }

}